package com.atguigu.tingshu.order.service.impl;

import com.alibaba.fastjson.JSON;
import com.atguigu.tingshu.account.client.UserAccountFeignClient;
import com.atguigu.tingshu.album.client.AlbumInfoFeignClient;
import com.atguigu.tingshu.album.client.TrackInfoFeignClient;
import com.atguigu.tingshu.common.constant.KafkaConstant;
import com.atguigu.tingshu.common.constant.RedisConstant;
import com.atguigu.tingshu.common.constant.SystemConstant;
import com.atguigu.tingshu.common.execption.GuiguException;
import com.atguigu.tingshu.common.result.Result;
import com.atguigu.tingshu.common.result.ResultCodeEnum;
import com.atguigu.tingshu.common.service.KafkaService;
import com.atguigu.tingshu.model.album.AlbumInfo;
import com.atguigu.tingshu.model.album.TrackInfo;
import com.atguigu.tingshu.model.order.OrderDerate;
import com.atguigu.tingshu.model.order.OrderDetail;
import com.atguigu.tingshu.model.order.OrderInfo;
import com.atguigu.tingshu.model.user.VipServiceConfig;
import com.atguigu.tingshu.order.helper.SignHelper;
import com.atguigu.tingshu.order.mapper.OrderDerateMapper;
import com.atguigu.tingshu.order.mapper.OrderDetailMapper;
import com.atguigu.tingshu.order.mapper.OrderInfoMapper;
import com.atguigu.tingshu.order.service.OrderInfoService;
import com.atguigu.tingshu.user.client.UserInfoFeignClient;
import com.atguigu.tingshu.user.client.VipServiceConfigFeignClient;
import com.atguigu.tingshu.vo.account.AccountDeductVo;
import com.atguigu.tingshu.vo.account.AccountLockResultVo;
import com.atguigu.tingshu.vo.account.AccountLockVo;
import com.atguigu.tingshu.vo.order.OrderDerateVo;
import com.atguigu.tingshu.vo.order.OrderDetailVo;
import com.atguigu.tingshu.vo.order.OrderInfoVo;
import com.atguigu.tingshu.vo.order.TradeVo;
import com.atguigu.tingshu.vo.user.UserInfoVo;
import com.atguigu.tingshu.vo.user.UserPaidRecordVo;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import io.seata.spring.annotation.GlobalTransactional;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RBlockingDeque;
import org.redisson.api.RDelayedQueue;
import org.redisson.api.RedissonClient;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Slf4j
@Service
@SuppressWarnings({"all"})
public class OrderInfoServiceImpl extends ServiceImpl<OrderInfoMapper, OrderInfo> implements OrderInfoService {

    @Autowired
    private OrderInfoMapper orderInfoMapper;

    @Autowired
    private UserInfoFeignClient userInfoFeignClient;

    @Autowired
    private AlbumInfoFeignClient albumInfoFeignClient;

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private TrackInfoFeignClient trackInfoFeignClient;

    @Autowired
    private VipServiceConfigFeignClient vipServiceConfigFeignClient;

    @Autowired
    private UserAccountFeignClient userAccountFeignClient;

    @Autowired
    private KafkaService kafkaService;

    @Autowired
    private OrderDerateMapper orderDerateMapper;

    @Autowired
    private OrderDetailMapper orderDetailMapper;

    @Autowired
    private RedissonClient redissonClient;



    @Override
    public IPage<OrderInfo> getUserPage(Page<OrderInfo> orderInfoPage, Long userId, String orderStatus) {
        //  调用mapper 层方法.
        IPage<OrderInfo> orderInfoIPage = this.orderInfoMapper.selectUserPage(orderInfoPage,userId,orderStatus);
        orderInfoIPage.getRecords().stream().forEach(orderInfo -> {
            //  支付名称
            orderInfo.setPayWayName(this.getPayWayName(orderInfo.getPayWay()));
            //  状态名称
            orderInfo.setOrderStatusName(this.getOrderStatusName(orderInfo.getOrderStatus()));
        });
        //  返回数据
        return orderInfoIPage;
    }

    /**
     * 获取订单支付状态。
     * @param orderStatus
     * @return
     */
    private String getOrderStatusName(String orderStatus) {
        //  获取订单支付状态
        return  orderStatus.equals(SystemConstant.ORDER_STATUS_UNPAID)?"未支付":orderStatus.equals(SystemConstant.ORDER_STATUS_PAID)?"已支付":"已取消";
    }

    @Override
    public OrderInfo getOrderInfo(String orderNo) {
        //  调用mapper
        return this.getOrderInfoByOrderNo(orderNo);
    }

    @Override
    public void orderCancel(long orderId) {
        //  根据订单Id 查询订单数据.
        OrderInfo orderInfo = this.getById(orderId);
        //  判断
        if (null != orderInfo && orderInfo.getOrderStatus().equals(SystemConstant.ORDER_STATUS_UNPAID)){
            //  取消订单
            orderInfo.setOrderStatus(SystemConstant.ORDER_STATUS_CANCEL);
            this.updateById(orderInfo);
        }
    }

    @Override
    @GlobalTransactional
    public String submitOrder(OrderInfoVo orderInfoVo, Long userId) {
        //  -- 接口验签 sign;
        //  工具类--对订单接口数据进行加密处理。除去sign参数，对提交数据对象进行排序，然后将值使用|连接。最后拼接一个固定字符串tingshu123
        String strJson = JSON.toJSONString(orderInfoVo);
        //  strJson 转换为Map
        Map map = JSON.parseObject(strJson, Map.class);
        map.put("payWay", "");
        //  调用校验方法.
        SignHelper.checkSign(map);

        //  -- 存储了流水号： 校验流水号
        String tradeNo = orderInfoVo.getTradeNo();
        //  获取到缓存的流水号
        String tradeNoKey = "tradeNo:" + userId;
        //  定义lua脚本：
        //  判断
        String scriptText = "if redis.call(\"get\",KEYS[1]) == ARGV[1]\n" +
                "then\n" +
                "    return redis.call(\"del\",KEYS[1])\n" +
                "else\n" +
                "    return 0\n" +
                "end";
        //  定义redisScript 对象
        DefaultRedisScript<Long> redisScript = new DefaultRedisScript<>();
        redisScript.setScriptText(scriptText);
        redisScript.setResultType(Long.class);
        Long count = (Long) this.redisTemplate.execute(redisScript, Arrays.asList(tradeNoKey), tradeNo);
        //  判断是否删除成功.
        if (count == 0) {
            throw new GuiguException(ResultCodeEnum.REPEAT_BUY_ERROR);
        }
        //  声明一个订单编号
        String orderNo = UUID.randomUUID().toString().replaceAll("-", "");
        //  判断支付方式：
        if (SystemConstant.ORDER_PAY_WAY_WEIXIN.equals(orderInfoVo.getPayWay())) {
            //  微信支付 -- 直接对接支付系统
            this.saveOrder(orderInfoVo,userId,orderNo);
        } else if (SystemConstant.ORDER_PAY_WAY_ALIPAY.equals(orderInfoVo.getPayWay())) {
            //  支付宝；--- 没有这个方式.
        } else {
            //  余额支付：
            //  1000--tingshu_account service-account；扣减  service-order；保存交易记录 tingshu_order;
            //  保存用户购买记录 service-user tingshu_user user_paid_album user_paid_track user_vip_service
            //  service-account service-order service-user;
            //  思考方式一：同时成功或失败；本地事务不能控制，使用分布式事务! -- seata
            //  思考方式二：扣减余额，保存订单必须成功；记录用户购买记录，可以失败. 使用异步操作！
            //  检查与锁定可用余额： 先判断当前账户余额是否能购买当前商品{专辑，声音，vip}
            //  声明一个对象
            try {
                //                AccountLockVo accountLockVo = new AccountLockVo();
                //                accountLockVo.setOrderNo(orderNo);
                //                accountLockVo.setAmount(orderInfoVo.getOrderAmount());
                //                accountLockVo.setUserId(userId);
                //                //  订单明细：专辑--title vip--name 声音-title
                //                accountLockVo.setContent("锁定" + orderInfoVo.getOrderDetailVoList().get(0).getItemName());
                //                //  远程调用：Result.ok(AccountLockResultVo);
                //                Result<AccountLockResultVo> result = userAccountFeignClient.checkAndLock(accountLockVo);
                //                Assert.notNull(result, "锁定结果集为空");
                //  创建对象 -- 检查与扣减
                AccountDeductVo accountDeductVo = new AccountDeductVo();
                accountDeductVo.setOrderNo(orderNo);
                accountDeductVo.setAmount(orderInfoVo.getOrderAmount());
                accountDeductVo.setUserId(userId);
                accountDeductVo.setContent("检查与扣减" + orderInfoVo.getOrderDetailVoList().get(0).getItemName());
                //  远程调用
                Result result = userAccountFeignClient.checkAndDeduct(accountDeductVo);
                //  判断
                if (200 != result.getCode()) {
                    //  抛出异常。
                    throw new GuiguException(ResultCodeEnum.ACCOUNT_LOCK_ERROR);
                }
                //  保存订单方法. 保存订单基本信息.order_info order_detail order_derate
                //  判断支付方式：余额-->记录用户购买信息{异步改为同步}，在线
                this.saveOrder(orderInfoVo,userId,orderNo);
                //  保存用户购买记录信息.
                OrderInfo orderInfo = this.getOrderInfoByOrderNo(orderNo);
                //  创建一个对象
                UserPaidRecordVo userPaidRecordVo = new UserPaidRecordVo();
                userPaidRecordVo.setOrderNo(orderNo);
                userPaidRecordVo.setUserId(orderInfo.getUserId());
                userPaidRecordVo.setItemType(orderInfo.getItemType());
                //  购买项目Id; 如果购买了专辑-albumId, 声音--trackId  vip--config.id
                //  需要查询订单明细.item_id
                List<Long> itemIdList = orderInfo.getOrderDetailList().stream().map(OrderDetail::getItemId).collect(Collectors.toList());
                userPaidRecordVo.setItemIdList(itemIdList);
                //  远程调用
                Result userResult = this.userInfoFeignClient.savePaidRecord(userPaidRecordVo);
                //  判断执行是否成功
                if (200 != userResult.getCode()){
                    throw new GuiguException(211, "新增购买记录异常");
                }
                //  发送消息异步扣减金额.
                //  this.kafkaService.sendMessage(KafkaConstant.QUEUE_ACCOUNT_MINUS,orderNo);
                //  返回订单编号
                return orderNo;
            } catch (GuiguException e) {
                //  如果出现异常，则解锁金额.
                //  this.kafkaService.sendMessage(KafkaConstant.QUEUE_ACCOUNT_UNLOCK,orderNo);
                //  log.error("账号锁定失败:"+orderNo);
                throw new GuiguException(ResultCodeEnum.ACCOUNT_LOCK_ERROR);
            }
        }
        //  返回订单编号.
        return orderNo;
    }

    /**
     * 保存订单 -- 哪些情况会导致事务失效?
     * @param orderInfoVo
     * @param userId
     * @param orderNo
     */
    @Transactional(rollbackFor = Exception.class)
    public void saveOrder(OrderInfoVo orderInfoVo, Long userId, String orderNo) {
        //  order_info order_detail order_derate
        OrderInfo orderInfo = new OrderInfo();
        //  赋值：
        BeanUtils.copyProperties(orderInfoVo,orderInfo);
        //  赋值user_id
        orderInfo.setUserId(userId);
        orderInfo.setOrderTitle(orderInfoVo.getOrderDetailVoList().get(0).getItemName());
        orderInfo.setOrderNo(orderNo);
        orderInfo.setOrderStatus(SystemConstant.ORDER_STATUS_UNPAID);
        this.save(orderInfo);
        //  this.orderInfoMapper.insert();
        //  保存订单明细
        List<OrderDetailVo> orderDetailVoList = orderInfoVo.getOrderDetailVoList();
        //  循环遍历
        if (!CollectionUtils.isEmpty(orderDetailVoList)){
            for (OrderDetailVo orderDetailVo : orderDetailVoList) {
                //  创建对象
                OrderDetail orderDetail = new OrderDetail();
                //  属性拷贝：
                BeanUtils.copyProperties(orderDetailVo,orderDetail);
                //  赋值orderId
                orderDetail.setOrderId(orderInfo.getId());
                this.orderDetailMapper.insert(orderDetail);
            }
        }
        //  保存减免
        List<OrderDerateVo> orderDerateVoList = orderInfoVo.getOrderDerateVoList();
        if (!CollectionUtils.isEmpty(orderDerateVoList)){
            //  循环遍历
            for (OrderDerateVo orderDerateVo : orderDerateVoList) {
                //  创建悐
                OrderDerate orderDerate = new OrderDerate();
                //  属性拷贝
                BeanUtils.copyProperties(orderDerateVo,orderDerate);
                //  赋值订单Id
                orderDerate.setOrderId(orderInfo.getId());
                //  保存数据
                this.orderDerateMapper.insert(orderDerate);
            }
        }
        //  判断支付方式
        if (orderInfoVo.getPayWay().equals(SystemConstant.ORDER_PAY_ACCOUNT)){
            //  余额支付：
            this.orderPaySuccess(orderNo);
        } else {
            //  在线支付：微信-支付宝; 发送一个消息，做延迟关单处理，15m,没有付款则取消订单. rabbitmq;--发送延迟消息：
            this.sendDelayMessage(orderInfo.getId());
        }
    }

    /**
     * 发送延迟消息.
     * @param orderId
     */
    private void sendDelayMessage(Long orderId) {
        try {
            //  redissonClient-- 发送延迟消息.
            RBlockingDeque<Object> blockingDeque = this.redissonClient.getBlockingDeque(KafkaConstant.QUEUE_ORDER_CANCEL);
            //  延迟队列。
            RDelayedQueue<Object> delayedQueue = this.redissonClient.getDelayedQueue(blockingDeque);
            //  向队列中存储数据.
            delayedQueue.offer(orderId.toString(),KafkaConstant.DELAY_TIME,TimeUnit.SECONDS);
            log.info("添加延时队列成功 ，延迟时间：{}，订单id：{}", KafkaConstant.DELAY_TIME, orderId);
        } catch (Exception e) {
            log.info("添加延时队列失败 ，延迟时间：{}，订单id：{}", KafkaConstant.DELAY_TIME, orderId);
            throw new RuntimeException(e);
        }
    }

    /**
     * 订单支付成功。
     * @param orderNo
     */
    public void orderPaySuccess(String orderNo) {
        //  修改订单状态. 变为已支付：
        //  update order_info set order_status = ? where order_no = ?;
        LambdaUpdateWrapper<OrderInfo> wrapper = new LambdaUpdateWrapper<>();
        wrapper.set(OrderInfo::getOrderStatus,SystemConstant.ORDER_STATUS_PAID);
        wrapper.eq(OrderInfo::getOrderNo,orderNo);
        this.update(wrapper);
        //
        //        OrderInfo orderInfo = new OrderInfo();
        //        orderInfo.setOrderStatus(SystemConstant.ORDER_STATUS_PAID);
        //        LambdaQueryWrapper<OrderInfo> queryWrapper = new LambdaQueryWrapper<>();
        //        queryWrapper.eq(OrderInfo::getOrderNo,orderNo);
        //        this.update(orderInfo,queryWrapper);
        //  需要根据订单orderNo 查询 orderInfo 对象。
        //        OrderInfo orderInfo = this.getOrderInfoByOrderNo(orderNo);
        //        //  创建一个对象
        //        UserPaidRecordVo userPaidRecordVo = new UserPaidRecordVo();
        //        userPaidRecordVo.setOrderNo(orderNo);
        //        userPaidRecordVo.setUserId(orderInfo.getUserId());
        //        userPaidRecordVo.setItemType(orderInfo.getItemType());
        //        //  购买项目Id; 如果购买了专辑-albumId, 声音--trackId  vip--config.id
        //        //  需要查询订单明细.item_id
        //        List<Long> itemIdList = orderInfo.getOrderDetailList().stream().map(OrderDetail::getItemId).collect(Collectors.toList());
        //        userPaidRecordVo.setItemIdList(itemIdList);
        //  发送消息，记录用户购买信息.
        //  this.kafkaService.sendMessage(KafkaConstant.QUEUE_USER_PAY_RECORD,JSON.toJSONString(userPaidRecordVo));

    }

    /**
     * 根据订单编号获取订单对象
     * @param orderNo
     * @return
     */
    private OrderInfo getOrderInfoByOrderNo(String orderNo) {
        //  查询订单对象
        OrderInfo orderInfo = this.getOne(new LambdaQueryWrapper<OrderInfo>().eq(OrderInfo::getOrderNo, orderNo));
        //  判断
        if (null != orderInfo){
            //  赋值订单明细结合
            //  select * from order_detail where order_id = ?;
            orderInfo.setOrderDetailList(orderDetailMapper.selectList(new LambdaQueryWrapper<OrderDetail>().eq(OrderDetail::getOrderId,orderInfo.getId())));
        }

        //  付款方式名称：
        orderInfo.setPayWayName(this.getPayWayName(orderInfo.getPayWay()));

        //  返回订单对象
        return orderInfo;
    }

    /**
     * 获取付款方式
     * @param payWay
     * @return
     */
    private String getPayWayName(String payWay) {
        //  获取数据
        return payWay.equals(SystemConstant.ORDER_PAY_ACCOUNT)?"余额":"在线";
    }


    @Override
    public OrderInfoVo trade(TradeVo tradeVo, Long userId) {
        //  创建对象
        OrderInfoVo orderInfoVo = new OrderInfoVo();
        //  原始金额
        BigDecimal originalAmount = new BigDecimal("0.00");
        //  减免金额
        BigDecimal derateAmount = new BigDecimal("0.00");
        //  实际金额
        BigDecimal orderAmount = new BigDecimal("0.00");
        //  订单明细
        List<OrderDetailVo> orderDetailVoList = new ArrayList<>();
        //  订单减免明细
        List<OrderDerateVo> orderDerateVoList = new ArrayList<>();

        //  获取用户信息.
        Result<UserInfoVo> userInfoVoResult = this.userInfoFeignClient.getUserInfoVo(userId);
        Assert.notNull(userInfoVoResult, "查询用户结果集为空");
        UserInfoVo userInfoVo = userInfoVoResult.getData();
        Assert.notNull(userInfoVo, "查询用户对象为空");
        //  本质是：给 orderInfoVo 赋值。
        //  判断购买类型
        if (SystemConstant.ORDER_ITEM_TYPE_ALBUM.equals(tradeVo.getItemType())) {
            //  购买专辑
            //  这个用户是否购买过专辑.
            Result<Boolean> isPaidAlbumResult = userInfoFeignClient.isPaidAlbum(tradeVo.getItemId());
            Assert.notNull(isPaidAlbumResult, "查询购买专辑结果集为空");
            Boolean resultData = isPaidAlbumResult.getData();
            //  返回true; 说明购买过.
            if (resultData) {
                throw new GuiguException(ResultCodeEnum.REPEAT_BUY_ERROR);
            }

            //  获取到当前专辑对象.
            Result<AlbumInfo> albumInfoResult = albumInfoFeignClient.getAlbumInfo(tradeVo.getItemId());
            Assert.notNull(albumInfoResult, "专辑结果集为空");
            AlbumInfo albumInfo = albumInfoResult.getData();
            Assert.notNull(albumInfo, "专辑对象为空");
            //  原始价格：
            originalAmount = albumInfo.getPrice();
            //  判断当前用户的身份.
            if (userInfoVo.getIsVip() == 1 && userInfoVo.getVipExpireTime().after(new Date())) {
                //  当前专辑有折扣. BigDecimal 如何防止进度损失 new BigDecimal("-1")
                //  0.1-9.9 不打折 -1
                if (albumInfo.getVipDiscount().compareTo(new BigDecimal("-1")) != 0) {
                    //  计算折扣金额. 100 8折;  100*(1-0.8); 20;
                    //  100-100*(10-8)/10;
                    derateAmount = originalAmount.subtract(originalAmount.multiply(new BigDecimal("10").subtract(albumInfo.getVipDiscount())).divide(new BigDecimal("10"), 2, RoundingMode.HALF_UP));
                }
            } else {
                //  0.1-9.9 不打折 -1
                if (albumInfo.getDiscount().compareTo(new BigDecimal("-1")) != 0) {
                    //  计算折扣金额. 100 8折;  100*(1-0.8); 20;
                    //  100-100*(10-8)/10;
                    derateAmount = originalAmount.subtract(originalAmount.multiply(new BigDecimal("10").subtract(albumInfo.getDiscount())).divide(new BigDecimal("10"), 2, RoundingMode.HALF_UP));
                }
            }
            //  实际价格：
            orderAmount = originalAmount.subtract(derateAmount);
            //  添加订单明细
            OrderDetailVo orderDetailVo = new OrderDetailVo();
            orderDetailVo.setItemId(tradeVo.getItemId());
            orderDetailVo.setItemName(albumInfo.getAlbumTitle());
            orderDetailVo.setItemPrice(orderAmount);
            orderDetailVo.setItemUrl(albumInfo.getCoverUrl());
            orderDetailVoList.add(orderDetailVo);
            //  添加订单减免明细
            if (derateAmount.compareTo(BigDecimal.ZERO) != 0) {
                //  声明减免对象
                OrderDerateVo orderDerateVo = new OrderDerateVo();
                //  赋值
                orderDerateVo.setDerateAmount(derateAmount);
                orderDerateVo.setDerateType(SystemConstant.ORDER_DERATE_ALBUM_DISCOUNT);
                orderDerateVoList.add(orderDerateVo);
            }
        } else if (SystemConstant.ORDER_ITEM_TYPE_TRACK.equals(tradeVo.getItemType())) {
            //  购买声音
            //  先获取用户购买的集数，如果购买集数<0 抛出异常.
            if (tradeVo.getTrackCount() < 0) {
                throw new GuiguException(ResultCodeEnum.ARGUMENT_VALID_ERROR);
            }
            //  获取声音列表  trackId=18654 count=10  -- 为了构建订单结算页的详情信息.
            Result<List<TrackInfo>> trackInfoListResult = trackInfoFeignClient.findPaidTrackInfoList(tradeVo.getItemId(), tradeVo.getTrackCount());
            Assert.notNull(trackInfoListResult, "声音列表返回结果集为空");
            List<TrackInfo> trackInfoList = trackInfoListResult.getData();
            Assert.notNull(trackInfoList, "声音列表对象为空");
            //  获取到专辑对象： trackInfoList.get(0).getAlbumId() === 每个声音对应的专辑Id 都一样.
            Result<AlbumInfo> albumInfoResult = this.albumInfoFeignClient.getAlbumInfo(trackInfoList.get(0).getAlbumId());
            Assert.notNull(albumInfoResult, "专辑返回结果集为空");
            AlbumInfo albumInfo = albumInfoResult.getData();
            Assert.notNull(albumInfo, "专辑对象为空");
            //  声音不支持折扣价; 需要知道总价，实际价格
            originalAmount = tradeVo.getTrackCount() == 0 ? albumInfo.getPrice() : albumInfo.getPrice().multiply(new BigDecimal(tradeVo.getTrackCount()));
            orderAmount = originalAmount;
            //  循环遍历赋值
            for (TrackInfo trackInfo : trackInfoList) {
                //  创建订单明细对象
                OrderDetailVo orderDetailVo = new OrderDetailVo();
                //  购买的声音Id
                //  orderDetailVo.setItemId(tradeVo.getItemId()); 用户点击的具体声音Id
                orderDetailVo.setItemId(trackInfo.getId()); // 用户要购买的声音Id
                orderDetailVo.setItemName(trackInfo.getTrackTitle());
                //  每个声音的单价.
                orderDetailVo.setItemPrice(albumInfo.getPrice());
                orderDetailVo.setItemUrl(trackInfo.getCoverUrl());
                orderDetailVoList.add(orderDetailVo);
            }

        } else {
            //  购买vip
            //  根据Id 获取到vip 配置信息 vip_service_config
            Result<VipServiceConfig> vipServiceConfigResult = vipServiceConfigFeignClient.getVipServiceConfig(tradeVo.getItemId());
            Assert.notNull(vipServiceConfigResult, "vip服务配置信息结果集为空");
            VipServiceConfig vipServiceConfig = vipServiceConfigResult.getData();
            Assert.notNull(vipServiceConfig, "vip服务配置对象为空");
            //  计算各种金额；
            originalAmount = vipServiceConfig.getPrice();
            orderAmount = vipServiceConfig.getDiscountPrice();
            derateAmount = originalAmount.subtract(orderAmount);

            //  赋值订单明细；减免明细;
            OrderDetailVo orderDetailVo = new OrderDetailVo();
            orderDetailVo.setItemId(tradeVo.getItemId());
            orderDetailVo.setItemName(vipServiceConfig.getName());
            orderDetailVo.setItemPrice(orderAmount);
            orderDetailVo.setItemUrl(vipServiceConfig.getImageUrl());

            orderDetailVoList.add(orderDetailVo);
            //  添加订单减免明细
            if (derateAmount.compareTo(BigDecimal.ZERO) != 0) {
                //  声明减免对象
                OrderDerateVo orderDerateVo = new OrderDerateVo();
                //  赋值
                orderDerateVo.setDerateAmount(derateAmount);
                orderDerateVo.setDerateType(SystemConstant.ORDER_DERATE_VIP_SERVICE_DISCOUNT);
                orderDerateVoList.add(orderDerateVo);
            }
        }
        //  给orderInfoVo 其他属性赋值：
        String tradeNo = UUID.randomUUID().toString().replaceAll("-", "");
        String tradeNoKey = "tradeNo:" + userId;
        //  将流水号存储到缓存
        this.redisTemplate.opsForValue().set(tradeNoKey, tradeNo, 1, TimeUnit.HOURS);
        //  交易号能够做到防止用户重复提交订单！ 交易号唯一：
        //  交易号给一个UUID;
        orderInfoVo.setTradeNo(tradeNo);
        orderInfoVo.setPayWay("");
        orderInfoVo.setItemType(tradeVo.getItemType());
        orderInfoVo.setOrderAmount(orderAmount);
        orderInfoVo.setOriginalAmount(originalAmount);
        orderInfoVo.setDerateAmount(derateAmount);
        orderInfoVo.setOrderDetailVoList(orderDetailVoList);
        orderInfoVo.setOrderDerateVoList(orderDerateVoList);
        //  时间戳;
        long timestamp = SignHelper.getTimestamp();
        orderInfoVo.setTimestamp(timestamp);
        //  签名：
        String str = JSON.toJSONString(orderInfoVo);
        Map map = JSON.parseObject(str, Map.class);
        //  工具类--对订单接口数据进行加密处理. 除去sign 参数，对提交数据对象进行排序，然后将值使用|连接。最后拼接一个固定字符串tingshu123 ,使用MD5加密
        String sign = SignHelper.getSign(map);
        orderInfoVo.setSign(sign);
        //  返回对象
        return orderInfoVo;
    }
}
